Demonstrating the Short Lag Spatial Coherence beamforming algorithm
This example script demonstates the Short Lag Spatial Coherence beamforming algorithm introduced in the article: Lediju, M. A., Trahey, G. E., Byram, B. C., & Dahl, J. J. (2011). Short-lag spatial coherence of backscattered echoes: Imaging characteristics. IEEE Transactions on Ultrasonics, Ferroelectrics, and Frequency Control, 58(7), 1377-1388. https://doi.org/10.1109/TUFFC.2011.1957
The algorithm is demonstrated on a dataset recorded from a standard CIRS phantom of string targets and a hyperechoic cyst. Also, the second part of the example uses a dataset recorded from the parasternal long axis of a human heart. The cardiac SLSC image reproduces the results in the article: Lediju Bell, M. A., Goswami, R., Kisslo, J. A., Dahl, J. J., & Trahey, G. E. (2013). Short-Lag Spatial Coherence (SLSC) Imaging of Cardiac Ultrasound Data: Initial Clinical Results. Ultrasound in Medicine & Biology, 39(10), 1861-1874. https://doi.org/10.1016/j.ultrasmedbio.2013.03.029 However, those results were from parasternal short axis and apical four chamber views, while we show images of the parasternal long axis.
by Ole Marius Hoel Rindal olemarius@olemarius.net and Muyinatu Lediju Bell mledijubell@jhu.edu 21.08.2017
Contents
- Reading the UFF dataset
- decimating the sequence -> too heavy for this example
- Defining scan for the FI (Focused Imaging) CIRS dataset
- Set up processing pipeline / Delay the channel data
- Create the Delay-And-Sum image
- Create the Short Lag Spatial Coherence (SLSC) image
- The reference of the SLSC process
- Display the SLSC image together with the DAS image
- Calculate the full correlation for all 63 lags
- SLSC on a cardiac image
- Create the images of the heart.
- Plot the two images
- Scan Conversion with interpolation
- References
Reading the UFF dataset
We'll start with reading the UFF dataset recorded from a CIRS phantom
close all; % data location url='http://ustb.no/datasets/'; % if not found download from here local_path = [ustb_path(),'/data/']; % location of example data addpath(local_path); % Choose dataset filename='Alpinion_L3-8_FI_hyperechoic_scatterers.uff'; % check if the file is available in the local path or downloads otherwise tools.download(filename, url, local_path); channel_data = uff.read_object([local_path, filename],'/channel_data'); channel_data.print_authorship
UFF: reading channel_data [uff.channel_data] UFF: reading sequence [uff.wave] [====================] 100% Name: FI dataset of hyperechoic cyst and points scatterers recorded on an Alpinion scanner with a L3-8 Probe from a CIRS General Purpose Ultrasound Phantom Reference: www.ultrasoundtoolbox.com Author(s): Ole Marius Hoel Rindal <olemarius@olemarius.net> Muyinatu Lediju Bell <mledijubell@jhu.edu> Version: 1.0.2
decimating the sequence -> too heavy for this example
channel_data.data=channel_data.data(:,:,1:2:256); channel_data.sequence=channel_data.sequence(1:2:256);
Defining scan for the FI (Focused Imaging) CIRS dataset
Define the scan from z = 0 to 55 mm, the x is defined from the transmit sequence origin position for each scan line.
z_axis=linspace(0e-3,55e-3,512).'; x_axis=zeros(channel_data.N_waves,1); for n=1:channel_data.N_waves x_axis(n) = channel_data.sequence(n).source.x; end scan=uff.linear_scan('x_axis',x_axis,'z_axis',z_axis);
Set up processing pipeline / Delay the channel data
We are using no apodization because the SLSC algorithm requires equally weighted channel data from all receive elements
mid=midprocess.das(); mid.dimension = dimension.transmit; mid.channel_data=channel_data; mid.scan=scan; mid.transmit_apodization.window=uff.window.scanline; mid.receive_apodization.window=uff.window.none; % This will result in a beamformed_data object with the delayed and not % summed channel data. b_data = mid.go();
USTB General beamformer MEX v1.1.2 .............done!
Create the Delay-And-Sum image
If we want the DAS image, we can simply sum them.
das = postprocess.coherent_compounding(); das.input = b_data; das_image = das.go(); figure(1); das_image.plot(subplot(121),['DAS'],60,'log');
Create the Short Lag Spatial Coherence (SLSC) image
We are using a kernel size equal to one wavelength, and use M = 10. See the article referenced for more details.
slsc = postprocess.short_lag_spatial_coherence(); slsc.receive_apodization = mid.receive_apodization; slsc.dimension = dimension.receive; slsc.channel_data = mid.channel_data; slsc.maxM = 10; slsc.input = b_data; slsc.K_in_lambda = 1; slsc_data = slsc.go();
The reference of the SLSC process
Let's look at the reference for the SLSC process. If you use the USTB and are using the SLSC process in your work you have to reference this reference according to our citation policy, see http://www.ustb.no/citation/
slsc.print_reference
Reference: Lediju, M. A., Trahey, G. E., Byram, B. C., & Dahl , J. J. (2011). Short-lag spatial coherence of bac kscattered echoes: Imaging characteristics. IEEE T ransactions on Ultrasonics, Ferroelectrics, and Fr equency Control, 58(7), 1377?1388. https://doi.org /10.1109/TUFFC.2011.1957Lediju Bell, M. A., Goswam i, R., Kisslo, J. A., Dahl, J. J., & Trahey, G. E. (2013). Short-Lag Spatial Coherence (SLSC) Imagin g of Cardiac Ultrasound Data: Initial Clinical Res ults. Ultrasound in Medicine & Biology, 39(10), 18 61?1874. https://doi.org/10.1016/j.ultrasmedbio.20 13.03.029
You can also give some credit to the authors of the implementation in your work ;)
slsc.print_implemented_by
Implemented by: Ole Marius Hoel Rindal <olemarius@olemarius.net>, Muyinatu A. Lediju Bell <mledijubell@jhu.edu>, Don gwoon Hyun <dhyun@stanford.edu>
Display the SLSC image together with the DAS image
Now, we can finally plot the SLSC image together with the DAS image.
figure(1) slsc_data.plot(subplot(122),['SLSC M = ',num2str(slsc.maxM)],[],'none'); caxis([0 1])
Calculate the full correlation for all 63 lags
The dataset was receving on 64 elements, thus we can calculate the full correlation values for all 63 lags if we want. Then, we can reproduce Fig 1. from Lediju, M. A., Trahey, G. E., Byram, B. C., & Dahl, J. J. (2011). Short-lag spatial coherence of backscattered echoes: Imaging characteristics. IEEE Transactions on Ultrasonics, Ferroelectrics, and Frequency Control, 58(7), 1377-1388. https://doi.org/10.1109/TUFFC.2011.1957
slsc.maxM = 63; slsc_data = slsc.go(); z_speckle = 327 x_speckle = 100 figure(2);clf;hold all; plot(squeeze(slsc.slsc_values(372,50,:)),'r','LineWidth',2,'DisplayName',... sprintf('Point target at x = %.2f, z = %.2f ',slsc_data.scan.x_axis(99)*1000,... slsc_data.scan.z_axis(372)*1000)) plot(ones(1,64),'r*','DisplayName','Theoretical point target') plot(squeeze(mean(mean(slsc.slsc_values(z_speckle-10:z_speckle+10,x_speckle-10:x_speckle+10,:),2),1)),'b','LineWidth',2,'DisplayName',... sprintf('Mean of speckle around x = %.2f, z = %.2f ',slsc_data.scan.x_axis(x_speckle)*1000,... slsc_data.scan.z_axis(z_speckle)*1000)) theoretical_speckle = ones(1,64)*64-linspace(1,64,64); plot(theoretical_speckle./max(theoretical_speckle(:)),'b*','DisplayName','Theoretical speckle') ylim([-0.5 1.2]); xlim([0 63]); xlabel('Lag (receive element spacing)'); ylabel('Correlation'); legend('show','Location','sw'); set(gca,'FontSize',14); title('Reproducing Fig. 1 in SLSC article');
z_speckle = 327 x_speckle = 100
SLSC on a cardiac image
Next, let's reproduce some of the results from the article : Lediju Bell, M. A., Goswami, R., Kisslo, J. A., Dahl, J. J., & Trahey, G. E. (2013). Short-Lag Spatial Coherence (SLSC) Imaging of Cardiac Ultrasound Data: Initial Clinical Results. Ultrasound in Medicine & Biology, 39(10), 1861-1874. https://doi.org/10.1016/j.ultrasmedbio.2013.03.029
close all; url = ['https://drive.google.com/uc?export=download' ... '&id=19OyvPCP4qUiTECFpUe8r3r_Ys2281j0N']; % if not found download from here % Choose dataset name = 'Verasonics_P2-4_parasternal_long_subject_1.uff'; % Create full filepath file = fullfile(data_path(), name); % check if the file is available in the local path or downloads otherwise tools.download(file, url) % read the data channel_data = uff.read_object(file,'/channel_data'); scan = uff.read_object(file,'/scan');
UFF: reading channel_data [uff.channel_data] UFF: reading sequence [uff.wave] [====================] 100% UFF: reading scan [uff.sector_scan] [====================] 100%
Print info about the dataset. Remeber that if you want to use this dataset you have to reference this article!
channel_data.print_authorship
Name: A human heart in apical four chamber view, scanned with the Verasonics Reference: Rindal, O. M. H., Aakhus, S., Holm, S., & Austeng, A. (2017). Hypothesis of Improved Visualization of Microstructures in the Interventricular Septum with Ultrasound and Adaptive Beamforming. Ultrasound in Medicine and Biology. https://doi.org/10.1016/j.ultrasmedbio.2017.05.023 Author(s): Ole Marius Hoel Rindal <olemarius@olemarius.no> Version: 1.0.0
Create the images of the heart.
Let's do the same as we did above and create the DAS and the SLSC image of this heart image cycle. Since the code is very similar, we are a bit cheap on the comments ;)
% For the online example we used all the 50 frames in the dataset, but, to % save time you can scale it down to the number of frames below, if not % comment the next line out. %channel_data.N_frames = 5; depth_axis=linspace(0e-3,110e-3,512).'; azimuth_axis=zeros(channel_data.N_waves,1); for n=1:channel_data.N_waves azimuth_axis(n) = channel_data.sequence(n).source.azimuth; end scan=uff.sector_scan('azimuth_axis',azimuth_axis,'depth_axis',depth_axis); mid=midprocess.das(); mid.dimension = dimension.transmit; mid.channel_data=channel_data; mid.scan=scan; mid.transmit_apodization.window=uff.window.scanline; mid.receive_apodization.window=uff.window.none; % This will result in a beamformed_data object with the delayed and not % summed channel data. b_data = mid.go(); % DAS image das = postprocess.coherent_compounding(); das.input = b_data; das_data = das.go();
USTB General beamformer MEX v1.1.2 .............done!
% SLSC image
slsc = postprocess.short_lag_spatial_coherence();
slsc.receive_apodization = mid.receive_apodization;
slsc.dimension = dimension.receive;
slsc.channel_data = channel_data;
slsc.maxM = 10;
slsc.input = b_data;
slsc.K_in_lambda = 1;
slsc_data = slsc.go();
Plot the two images
das_data.plot(3,['DAS']); slsc_data.plot(4,['SLSC'],[],'none'); caxis([0 1])
Scan Conversion with interpolation
Use the scan conversion from the tools. This is a bit more tricky than the built in, but it adds some interpolation making a final smoother image.
% Get the angles as an array for tx = 1:numel(channel_data.sequence) transmit_angles(tx) = channel_data.sequence(tx).source.azimuth; end % Get all the SLSC images as an matrix of images slsc_images = slsc_data.get_image('none'); das_images = das_data.get_image('log'); %das_images = das_images./max(das_images(:)); % Do the scan conversion for each frame. We are asking for a final image of % 512x512 samples. for frame = 1:channel_data.N_frames [slsc_interpolated(:,:,frame), Xs, Zs] = tools.scan_convert(slsc_images(:,:,frame),... transmit_angles,das_data.scan.depth_axis',512,512); [das_interpolated(:,:,frame), Xs, Zs] = tools.scan_convert(das_images(:,:,frame),... transmit_angles,das_data.scan.depth_axis',512,512); end % Put the data back into uff.beamformed data objects and show them! slsc_beamformed_img = uff.beamformed_data(); slsc_beamformed_img.scan = uff.linear_scan(); slsc_beamformed_img.scan.x_axis = Xs; slsc_beamformed_img.scan.z_axis = Zs; slsc_beamformed_img.data = reshape(slsc_interpolated,... size(slsc_interpolated,1)*size(slsc_interpolated,2),size(slsc_interpolated,3)); slsc_beamformed_img.data(slsc_beamformed_img.data==0) = 1; %Make the background white slsc_beamformed_img.plot(5,'SLSC interpolated',60,'none'); caxis([0 1]); das_beamformed_img = uff.beamformed_data(); das_beamformed_img.scan = uff.linear_scan(); das_beamformed_img.scan.x_axis = Xs; das_beamformed_img.scan.z_axis = Zs; das_beamformed_img.data = reshape(das_interpolated,... size(das_interpolated,1)*size(das_interpolated,2),size(das_interpolated,3)); das_beamformed_img.plot(6,'DAS interpolated',60,'none'); caxis([-60 0]);
Error using griddedInterpolant The sample points arrays must have the same size as the sample values array. Error in interp2>makegriddedinterp (line 226) F = griddedInterpolant(varargin{:}); Error in interp2 (line 134) F = makegriddedinterp(X, Y, V, method,extrap); Error in tools.scan_convert (line 46) scanConvertedImage = interp2(double(thetaGrid), double(rangeGrid), double(inputImage), double(thetaGridOut), double(rangeGridOut), interpolationMethod,0); Error in FI_UFF_short_lag_spatial_coherence (line 233) [slsc_interpolated(:,:,frame), Xs, Zs] = tools.scan_convert(slsc_images(:,:,frame),...
References
Please see our citation policy http://www.ustb.no/citation/.
If you want to use the SLSC process with the USTB you need to reference this article:
Lediju, M. A., Trahey, G. E., Byram, B. C., & Dahl, J. J. (2011). Short-lag spatial coherence of backscattered echoes: Imaging characteristics. IEEE Transactions on Ultrasonics, Ferroelectrics, and Frequency Control, 58(7), 1377-1388. https://doi.org/10.1109/TUFFC.2011.1957
If you want to use it with cardiac imaging, you also need to reference this article:
Lediju Bell, M. A., Goswami, R., Kisslo, J. A., Dahl, J. J., & Trahey, G. E. (2013). Short-Lag Spatial Coherence (SLSC) Imaging of Cardiac Ultrasound Data: Initial Clinical Results. Ultrasound in Medicine & Biology, 39(10), 1861-1874. https://doi.org/10.1016/j.ultrasmedbio.2013.03.029
If you want to use the dataset from the CIRS phantom, see http://www.ustb.no/ustb-datasets/ and reference the USTB reference.
If you want to use the parasternal long axis cardiac dataset you need to reference this paper. See also http://www.ustb.no/ustb-datasets/:
Rindal, O. M. H., Aakhus, S., Holm, S., & Austeng, A. (2017). Hypothesis of Improved Visualization of Microstructures in the Interventricular Septum with Ultrasound and Adaptive Beamforming. Ultrasound in Medicine and Biology, 43(10), 2494?2499. https://doi.org/10.1016/j.ultrasmedbio.2017.05.023
If you have any questions you can contact the authors of this example.